package cn.yym.test.dao.impl;


import cn.yym.test.dao.PeopleDao;
import cn.yym.test.domain.People;
import cn.yym.test.utils.DataUtils;
import cn.yym.test.utils.DbUtils;
import cn.yym.test.utils.PageBean;

import java.sql.*;
import java.util.Date;
import java.util.List;

/**
 * @author admin
 */
public class PeopleDaoImpl implements PeopleDao {

    /**
     * 动态sql.
     *  select id, name, gender, email, birthday, createTime, updateTime
     *            from people where 1 = 1 and birthday > begin and name like ? and gender = ?
     *              and birthday < end limit ?, ?
     *
     *  select id, name, gender, email, birthday, createTime, updateTime
     *          from people where 1= 1 and  birthday > begin
     *
     *  select id, name, gender, email, birthday, createTime, updateTime
     *         from people where gender = ?
     *
     *  select id, name, gender, email, birthday, createTime, updateTime
     *         from people
     */
    // http://localhost:8081/web_project_war_exploded/people?currentPage=abc
    @Override
    public PageBean<People> getPageDate(String name, String gender, Date begin, Date end, int currentPage) {
        PageBean<People> pageBean = new PageBean<>();
        /**
         * 因为恶意用户用户 ：http://localhost:8081/web_project_war_exploded/people?currentPage=-20
         *                  http://localhost:8081/web_project_war_exploded/people?currentPage=2000
         * 获取总数的目的，是为了获取总的页数，为了防止用户的恶心访问，所谓的恶心访问是直接通过浏览器地址栏的
         * 方式进行访问，传入的currrentPage可能为负数或者大于总页数。
         */
        //获取满足条件的总的数量, 就可以得到总的页数, 因为总页数是根据总数据量和每页的数据量来得到的。
        int total = getTotal(name, gender, begin, end);

        // 如果满足条件的总数据量为0，那么就没必要查询分页的数据了，直接返回
        if(total == 0) {
            pageBean.setDatas(null);
            return pageBean;
        }

        //设置总的数据量(记录数)
        pageBean.setTotal(total);

        int pageSize = pageBean.getPageSize(); //每页的数量, 默认是10
        /**
         * 通用sql部分后面写 where 1 = 1目的，是因为查询的时候有很多动态条件，我们无法确定哪个判断条件
         * 会成为 where 后面的第一个条件, 而where后的第一个判断条件和其他的判断条件的区别在于没有 "and"
         */
        StringBuffer commonSql = new StringBuffer("select id, name, gender, email, birthday, " +
                "createTime, updateTime from people where 1 = 1 ");

        // 拼接sql格都的时候，各位亲哥，前后把空带上。！！！！
        if(null != name && !"".equals(name.trim())) {
            commonSql.append(" and name like ? ");
        }

        // 因为前后端都约定好了，查询所有是 -1, 前段gender的下拉框有个数据是 <option value="-1">所有</option>
        if(!"-1".equals(gender)) {
            commonSql.append(" and gender = ? ");
        }

        // 查询生日的开始日期
        if(null != begin) {
            commonSql.append(" and birthday > ?");
        }

        // 查询生日的结束日期
        if(null != end) {
            commonSql.append(" and birthday < ?");
        }

        commonSql.append(" limit ?, ? ");  //分页的语法sql

        // select id, name, gender, email, birthday, createTime, updateTime
        // from people where 1 = 1 and gender = ?  and birthday < ?  limit ?, ?

        Connection connection = DbUtils.getConnection();
        try {
            PreparedStatement ps = connection.prepareStatement(commonSql.toString());

            int i = 0;  // i的目的是因为我们无法确定谁是第一个参数, 就通过 ++i的方式来确定参数的位置

            // if判断的顺序必须和上面的拼接的sql的顺序保持一致
            if(null != name && !"".equals(name.trim())) {
                ps.setObject(++i, "%" + name + "%");
            }

            if(!"-1".equals(gender)) {
                ps.setObject(++i, gender);
            }

            if(null != begin) {
                ps.setObject(++i, begin);
            }

            if(null != end) {
                ps.setObject(++i, end);
            }

            //int totalPage = pageBean.getTotalPage(); //获取总的页数

            //设置当前页，将用户实际传入的当前页(currentPage) 放到代码中进行处理。
            pageBean.setCurrentPage(currentPage);

            // 再取正常值
            currentPage = pageBean.getCurrentPage();

            /**
             * 分页的时候索引的位置：如果为第1页，开始索引为0
             *                     如果为第5页，开始索引为40
             *                     如果为第8页，开始索引为70
             * 目前先考虑正常情况，代码这里的currentPage可以是一个有误的值，有误的值是因为用户的恶意操作：
             * http://localhost:8081/web_project_war_exploded/people?currentPage=-20
             */
            int beginIndex = (currentPage - 1) * pageSize;  // limit ?

            ps.setObject(++i, beginIndex); //设置分页的开始索引位置
            ps.setObject(++i, pageSize);  // 每页的数据量

            ResultSet rs = ps.executeQuery();  //执行查询

            List<People> list = DataUtils.getAll(People.class, rs);

            pageBean.setDatas(list); //往PageBean中设置当前分页的数据
            //pageBean.setCurrentPage(currentPage);  //设置当前页

            DbUtils.colse(rs, ps, connection);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return pageBean;
    }



    /**
     * 查询满足的条件的总的数据量的目的是为了获取总的页数,为了防止用户的恶心访问，所谓的恶心访问时直接通过浏览器地址栏的
     * 方式进行访问，传入的currentPage可能为负数大于总页数
     * @return
     */
    private int getTotal(String name, String gender, Date begin, Date end) {
        int total = 0;
        StringBuffer countCommonSql = new StringBuffer("select count(*) from people where 1 = 1 ");

        // 拼接sql的时候，各位亲哥，前后把空格都带上。！！！！
        if(null != name && !"".equals(name.trim())) {
            countCommonSql.append(" and name like ? ");
        }

        // 因为前后端都约定好了，查询所有是 -1, 前段gender的下拉框有个数据是 <option value="-1">所有</option>
        if(!"-1".equals(gender)) {
            countCommonSql.append(" and gender = ? ");
        }

        // 查询生日的开始日期
        if(null != begin) {
            countCommonSql.append(" and birthday > ? ");
        }

        // 查询生日的结束日期
        if(null != end) {
            countCommonSql.append(" and birthday < ? ");
        }

        Connection connection = DbUtils.getConnection();

        try {
            PreparedStatement ps = connection.prepareStatement(countCommonSql.toString());

            int i = 0;  // i的目的是因为我们无法确定谁是第一个参数, 就通过 ++i的方式来确定参数的位置

            // if判断的顺序必须和上面的拼接的sql的顺序保持一致
            if(null != name && !"".equals(name.trim())) {
                ps.setObject(++i, "%" + name + "%");
            }

            if(!"-1".equals(gender)) {
                ps.setObject(++i, gender);
            }

            if(null != begin) {
                ps.setObject(++i, begin);
            }

            if(null != end) {
                ps.setObject(++i, end);
            }

            ResultSet resultSet = ps.executeQuery();  //执行查询

            /**
             * +----------+
             * | count(*) |
             * +----------+
             * |        0 |
             * +----------+
             */
            resultSet.next();  // 原因是查询的数据就一行一列的数据, 绝对不会产生多行, 因为是 count(*)

            total = resultSet.getInt(1);

            DbUtils.colse(resultSet, ps, connection);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return total;
    }

    //根据用户的id删除用户
    @Override
    public void deletePeopleById(Integer id) {
        Connection conn = DbUtils.getConnection();
        String sql = "delete from people where id = ?";
        try {
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setObject(1, id);
            ps.executeUpdate();
            DbUtils.colse(null, ps, conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public People getPeopleById(Integer id) {
        Connection conn = DbUtils.getConnection();
        String sql = "select id, name, gender, email, birthday from people where id = ?";
        People people = null;
        try {
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setObject(1, id);

            ResultSet rs = ps.executeQuery();
            rs.next();
            people = new People(rs.getInt("id"), rs.getString("name"),
                    rs.getString("gender"), rs.getString("email"), rs.getDate("birthday"));

            DbUtils.colse(rs, ps, conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return people;
    }

    @Override
    public void editPeople(Integer id, String name, String gender, Date birthday, String email) {
        Connection conn = DbUtils.getConnection();
        String sql = "update people set name = ?, birthday = ?, gender = ?, email = ?, updateTime =? where id = ?";
        try {
            PreparedStatement ps = conn.prepareStatement(sql);

            // 构建一个Timestamp对象对象，构造方法中接受一个long (GMT时间对应时间), 从1970-1-1 凌晨到目前的时间
            Timestamp timestamp = new Timestamp(new Date().getTime());

            ps.setObject(1, name);
            ps.setObject(2, birthday);
            ps.setObject(3, gender);
            ps.setObject(4, email);
            ps.setObject(5, timestamp);
            ps.setObject(6, id);

            ps.executeUpdate();
            DbUtils.colse(null, ps, conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
